Here's my code. It's a function named `->address` that accepts `pubkey` data, concats together one sequence of `version+hash160+checksum` bytes, and base58 encodes it.
;; ByteArray -> String
(defn ->address [pubkey]
(let [ver (into-byte-array [0x00])
hash160 (crypto/hash160 pubkey) ;; (hash160 _) is (rmd160 (sha256 _))
ver+hash160 (concat-bytes ver hash160)
checksum (crypto/calc-checksum ver+hash160)
ver+hash160+checksum (concat-bytes ver+hash160 checksum)]
(base58-encode ver+hash160+checksum)))
(->address "0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6")
;;=> "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"
The version-byte is actually determined by the network:
(def networks
{:mainnet {:address/ver (byte 0x00)}
:testnet3 {:address/ver (byte 0x6f)}})
Also, if you base58-encode a byte-array with leading 0-bytes, each 0-byte gets converted into a "1".
From bitcoin's
test suite, "00000000000000000000" (hex) gets base58-encoded into "1111111111" (string).
In general, if the wiki doesn't help you, then check out any of the 50 partial bitcoin implementations and cross-examine them.